package com.soccertgc
{
	import com.soccertgc.config.Configuration;
	import com.soccertgc.core.User;
	import com.soccertgc.core.cards.Collection;
	import com.soccertgc.core.cards.Deck;
	import com.soccertgc.logging.IDumpable;
	import com.soccertgc.logging.LogTarget;
	import com.soccertgc.logging.LogTargetFactory;
	import com.soccertgc.logging.LogTargetParams;
	import com.soccertgc.logging.Logger;
	import com.soccertgc.utils.ErrorUtils;
	import com.soccertgc.utils.JsonUtils;
	
	import flash.system.Capabilities;
	import flash.system.Security;

	public class Application implements IDumpable
	{

		// -------------------------------------------------------------------------------
		// CONSTANTS
		// -------------------------------------------------------------------------------	
		
		// Application states
		public static const		STATE_START:String					= "StartState";
		public static const		STATE_LOGIN:String					= "StateLogin";
		public static const		STATE_MAIN_MENU:String				= "StateMenu";
		public static const		STATE_DECK_EDITOR:String			= "StateDeckEditor";
		public static const		STATE_DEBUG:String					= "StateDebug";
		
		// Application version
		public static const		NAME:String							= "Soccer TCG Flash Client";
		public static const		VERSION:Version						= new Version(VersionType.ALPHA,
																				  0, 		// major
																				  2, 		// minor
																				  10, 		// release
																				  "170",	// build
																				  "Franco");// codename
		
		// -------------------------------------------------------------------------------
		// STATIC
		// -------------------------------------------------------------------------------
		
		private static const _instance:Application = new Application();
		
		public static function get instance():Application
		{
			return _instance;
		}	
		
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		private var _initialized:Boolean;
		private var _user:User;
		private var _collection:Collection;
		private var _config:Configuration;
		// private var _logger:ILogger;
		// private var _ui:mx.core.Application;
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTOR
		// -------------------------------------------------------------------------------
		
		public function Application()
		{
			if(_instance)
				throw new Error( "Application Singleton can only be accessed through Application.instance" );
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------
		
		public function get isInit():Boolean
		{
			return _initialized;
		}
		
		public function get isDebug():Boolean
		{
			return _config.debugOptions.enabled;
		}
		
		public function get isUserLogged():Boolean
		{
			return _user.isLoggedIn;
		}
		
		public function get config():Configuration
		{
			return _config;
		}	
		
		public function get user():User
		{
			return _user;
		}

		protected function set user(value:User):void
		{
			_user = value;
		}

		public function get collection():Collection
		{
			return _collection;
		}
		
		protected function set collection(value:Collection):void
		{
			_collection = value;
		}
		
		public function get hasCollection():Boolean
		{
			return _collection.loaded;
		}

		
		// -------------------------------------------------------------------------------
		// PRIVATE METHODS
		// -------------------------------------------------------------------------------
		
		// Initialization
		
		private function initSystem():void
		{
		}
		
		private function initLog():void
		{
			try
			{
				// Iinit the logger
				Logger.init(_config.debugOptions, _config.logOptions);
			} 
			catch(error:Error) 
			{
				// Compose the message
				var messages:Array = new Array();
				messages.push("Log init failed: " + error.message);
				messages.push("");
				messages.push(ErrorUtils.toArray(error));
				// Trace the error
				traceError(messages);
				// LT_TODO: gestire un evento per la centralizzazione degli errori a livello applicazione 
				// throw new Error(message);
			}
		}
		
		private function initData():void
		{
			// Data initialization
			_user		= new User();
			_collection	= new Collection();
		}
		
		private function checkInit():void
		{
			if (!_instance.isInit) throwNotInitError(); 
		}
		
		// User interface and events
		
		// Tracing methods
		
		private function formatMessage(message:String = "", pad:Boolean = false):String
		{
			return Logger.format(message, pad);
		}
		
		private function traceMessage(messages:Array):void
		{
			trace("");
			trace(formatMessage("APPLICATION MESSAGE", true));
			for (var i:int = 0; i < messages.length; i++) trace(formatMessage(messages[i]));
			trace(formatMessage("", true));
			trace("");			
		}
		
		private function traceError(messages:Array):void
		{
			trace("");
			trace(formatMessage("APPLICATION ERROR", true));
			for (var i:int = 0; i < messages.length; i++) trace(formatMessage(messages[i]));
			trace(formatMessage("", true));
			trace("");
		}
		
		// Utility methods
		
		/**
		 * Method automatically called after application init, placeholder to contain code to test 
		 */
		protected function test():void
		{
			
			
			Logger.info("--- APPLICATION TEST --------------------");
			Logger.info("");
			
			
			//var json:String = JsonUtils.encode(Application.instance.config);
			//var json2:String = JSON.stringify(Application.instance.config);
			// Logger.debug("config json 1: " + json);
			// Logger.debug("config json 2: " + json2);
			
			/*
			// EnumTest01
			
			var e1:EnumTest01 = EnumTest01.ITEM01;
			
			var e2:EnumTest02 = EnumTest02.YES;
			
			
			var e01Item01:EnumTest01 = EnumTest01.ITEM01;
			var e01Item02:EnumTest01 = EnumTest01.ITEM02;
			
			var e01ItemById:EnumTest01 = EnumTest01.getById(1);
			
			var e01List:Array = EnumTest01.list();
			var e01Names:Array = EnumTest01.names();
			
			Logger.debug("EnumTest01 item 1: {0}", e01Item01);
			Logger.debug("EnumTest01 item 2: {0}", e01Item02);
			
			// EnumTest02
			
			var e02Item01:EnumTest02 = EnumTest02.YES;
			var e02Item02:EnumTest02 = EnumTest02.NO;
			
			var e02ItemById:EnumTest02 = EnumTest02.getById(4);
			
			var e02ItemBySign:EnumTest02 = EnumTest02.getBySign("s");
			
			var e02List:Array = EnumTest02.list();
			var e02Names:Array = EnumTest02.names();
			
			Logger.debug("EnumTest02 item 1: {0}", e02Item01);
			Logger.debug("EnumTest02 item 2: {0}", e02Item02);
			
			
			Logger.info("");
			Logger.info("--- APPLICATION TEST --------------------");
			*/
		}
		
		// Error throwing
		
		private function throwNotInitError():void
		{
			throw new Error("Application is not initialized!");
		}
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
		
		/**
		 * Initialize the application 
		 * @param ui Main UI reference used by the application
		 * @param config
		 */		
		public function init(config:Configuration):void
		{
			// Save the configuration
			_config = config;
			// Flex system init
			initSystem();
			// Log init
			initLog();
			// Data init
			initData();
			// Init done
			_initialized = true;
			// Log application start (LT_TODO > aggiungere un po di dati del client)
			Logger.info("");
			Logger.info(formatMessage("", true));
			Logger.info(formatMessage(com.soccertgc.Application.NAME));
			Logger.info(formatMessage("Version {0}"), com.soccertgc.Application.VERSION.toString());
			Logger.info(formatMessage("Player: {0} (type: {1}) {2}"), Capabilities.version, Capabilities.playerType, Capabilities.isDebugger ? "DEBUG" : "");
			Logger.info(formatMessage("Sandbox: {0}"), Security.sandboxType);
			Logger.info(formatMessage("", true));
			
			// If in debug, perform the tests
			if (isDebug) test();
		}
		
		/**
		 * 
		 * @param userData
		 * @param collectionData
		 * @param deckListData
		 * @param activeDeckData
		 */
		public function login(userData:Object, collectionData:Object, deckListData:Object, activeDeckData:Object):void
		{
			// User data loading
			_user.load(userData);
			// Collection loading
			_collection.load(collectionData);
			// Decks list creation 
			var decks:Array = deckListData.list;
			// Active deck reference
			var activeDeck:Deck = null;
			// Loop over definitions
			for (var i:int = 0; i<decks.length; i++)
			{
				// Deck creation
				var deckData:Object = decks[i];
				var deck:Deck = _collection.createNewDeck(deckData.id, deckData.name);
				// Sets the active deck
				if (deckData.active == 1) activeDeck = deck;
			}
			// Load the current active deck
			activeDeck.load(activeDeckData);
			// Set the active deck
			_collection.activeDeck = activeDeck;
			// INFO > User login
			Logger.info("User {0} login!", _user.username);
		}
		
		/**
		 * Logout the current loggd user and clears all the data 
		 */		
		public function logout():void
		{
			// INFO > User login
			Logger.info("User {0} logout!", _user.username);
			// Clears the application data
			_collection.unload();
			_user.unload();
		}

		/**
		 * 
		 * @param relativeUrl
		 * @return  
		 */		
		public function getAbsoluteCallUrl(relativeUrl:String):String
		{
			return Application.instance.config.callsUrl + relativeUrl;
		}
		
		/**
		 *  
		 * @param addDelimiters
		 * @return 
		 */		
		public function dump(source:Array = null, indentDepth:int = 0):Array
		{
			// Flag to add decoretors
			var decorate:Boolean = source == null || source.length == 0; 
			// 
			var dump:Array = source == null ? new Array() : source;

			// Decorator
			if (decorate) dump.push("");
			if (decorate) dump.push(formatMessage(NAME.toUpperCase() + " [v " + VERSION + "]", true));
			dump.push(formatMessage(""));
			dump.push(formatMessage("<< CONFIGURATION -------------------------------------"));
			dump.push(formatMessage(""));
			dump = _config.dump(dump, 0);
			dump.push(formatMessage(""));
			dump.push(formatMessage("<< USER ----------------------------------------------"));
			dump.push(formatMessage(""));
			dump = _user.dump(dump, 0);
			dump.push(formatMessage(""));
			dump.push(formatMessage("<< COLLECTION ----------------------------------------"));
			dump.push(formatMessage(""));
			dump = _collection.dump(dump, 0);
			
			// // Decorator footer
			if (decorate) dump.push(formatMessage(""));
			if (decorate) dump.push(formatMessage(NAME.toUpperCase() + " [v " + VERSION + "]", true));
			if (decorate) dump.push("");
			
			return dump;
		}
		
		// -------------------------------------------------------------------------------
		// STATIC METHODS
		// -------------------------------------------------------------------------------		
		
	}
}